#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
HQ-Reader macOS DMG 创建脚本
为macOS应用程序创建标准的DMG安装包
"""

import os
import sys
import shutil
import subprocess
import tempfile
from pathlib import Path
from datetime import datetime


class DMGCreator:
    """DMG创建器"""
    
    def __init__(self, app_name="HQ-Reader", app_version="1.0.0"):
        self.app_name = app_name
        self.app_version = app_version
        # 项目根目录是packaging文件夹的上级目录
        self.project_root = Path(__file__).parent.parent
        self.dist_dir = self.project_root / "dist"
        self.app_path = self.dist_dir / f"{app_name}.app"
        
        # DMG配置
        self.dmg_name = f"{app_name}_{app_version}_macOS"
        self.dmg_path = self.dist_dir / f"{self.dmg_name}.dmg"
        self.volume_name = f"{app_name} {app_version}"
        
    def log(self, message, level="INFO"):
        """打印日志"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        colors = {
            "INFO": "\033[94m",
            "SUCCESS": "\033[92m", 
            "WARNING": "\033[93m",
            "ERROR": "\033[91m",
            "HEADER": "\033[95m\033[1m"
        }
        color = colors.get(level, "\033[0m")
        print(f"{color}[{timestamp}] {level}: {message}\033[0m")
        
    def check_requirements(self):
        """检查创建DMG的要求"""
        self.log("检查DMG创建要求...", "HEADER")
        
        # 检查是否在macOS上
        if not sys.platform.startswith('darwin'):
            self.log("DMG只能在macOS上创建", "ERROR")
            return False
            
        # 检查应用程序包是否存在
        if not self.app_path.exists():
            self.log(f"应用程序包不存在: {self.app_path}", "ERROR")
            return False
            
        self.log(f"找到应用程序包: {self.app_path}", "SUCCESS")
        
        # 检查hdiutil命令
        try:
            subprocess.run(["hdiutil", "help"], 
                         capture_output=True, check=True)
            self.log("hdiutil工具可用", "SUCCESS")
        except (subprocess.CalledProcessError, FileNotFoundError):
            self.log("hdiutil工具不可用", "ERROR")
            return False
            
        return True
        
    def create_dmg_structure(self, temp_dir):
        """创建DMG内部结构"""
        self.log("创建DMG内部结构...", "HEADER")
        
        # 创建临时DMG内容目录
        dmg_content = Path(temp_dir) / "dmg_content"
        dmg_content.mkdir(exist_ok=True)
        
        # 复制应用程序包
        app_dest = dmg_content / f"{self.app_name}.app"
        self.log(f"复制应用程序包到: {app_dest}")
        shutil.copytree(self.app_path, app_dest, symlinks=True)
        
        # 创建应用程序文件夹的符号链接
        applications_link = dmg_content / "Applications"
        self.log("创建Applications文件夹符号链接")
        applications_link.symlink_to("/Applications")
        
        # 创建README文件
        readme_content = f"""# {self.app_name} {self.app_version}

## 安装说明

1. 将 {self.app_name}.app 拖拽到 Applications 文件夹
2. 在启动台或应用程序文件夹中找到 {self.app_name}
3. 双击启动应用程序

## 系统要求

- macOS 10.14 或更高版本
- 64位处理器

## 卸载

要卸载应用程序，只需将 {self.app_name}.app 从应用程序文件夹移到废纸篓。

---
© 2024 HQ-Reader Team. All rights reserved.
"""
        
        readme_file = dmg_content / "README.txt"
        with open(readme_file, 'w', encoding='utf-8') as f:
            f.write(readme_content)
            
        self.log(f"创建README文件: {readme_file}")
        
        return dmg_content
        
    def set_dmg_appearance(self, dmg_content):
        """设置DMG外观"""
        self.log("设置DMG外观...", "HEADER")
        
        # 创建.DS_Store文件来设置图标位置和窗口大小
        ds_store_script = f'''
tell application "Finder"
    tell disk "{self.volume_name}"
        open
        set current view of container window to icon view
        set toolbar visible of container window to false
        set statusbar visible of container window to false
        set the bounds of container window to {{100, 100, 600, 400}}
        set viewOptions to the icon view options of container window
        set arrangement of viewOptions to not arranged
        set icon size of viewOptions to 128
        set background picture of viewOptions to file ".background:background.png"
        set position of item "{self.app_name}.app" of container window to {{150, 200}}
        set position of item "Applications" of container window to {{350, 200}}
        close
        open
        update without registering applications
        delay 2
    end tell
end tell
'''
        
        # 创建背景图片目录
        background_dir = dmg_content / ".background"
        background_dir.mkdir(exist_ok=True)
        
        # 创建简单的背景图片（如果有的话）
        background_file = background_dir / "background.png"
        if not background_file.exists():
            # 创建一个简单的背景色
            self.log("创建默认背景", "INFO")
            
        return ds_store_script
        
    def create_dmg_file(self, dmg_content):
        """创建DMG文件"""
        self.log("创建DMG文件...", "HEADER")
        
        # 删除已存在的DMG文件
        if self.dmg_path.exists():
            self.dmg_path.unlink()
            self.log(f"删除已存在的DMG: {self.dmg_path}")
            
        # 计算所需大小（应用程序大小 + 50MB缓冲）
        app_size = self._get_directory_size(dmg_content)
        dmg_size = max(app_size + 50 * 1024 * 1024, 100 * 1024 * 1024)  # 至少100MB
        dmg_size_mb = dmg_size // (1024 * 1024)
        
        self.log(f"DMG大小: {dmg_size_mb}MB")
        
        try:
            # 创建临时DMG
            temp_dmg = self.dist_dir / f"{self.dmg_name}_temp.dmg"
            
            # 创建空白DMG
            cmd_create = [
                "hdiutil", "create",
                "-srcfolder", str(dmg_content),
                "-volname", self.volume_name,
                "-fs", "HFS+",
                "-fsargs", "-c c=64,a=16,e=16",
                "-format", "UDRW",
                "-size", f"{dmg_size_mb}m",
                str(temp_dmg)
            ]
            
            self.log("创建临时DMG...")
            result = subprocess.run(cmd_create, capture_output=True, text=True)
            if result.returncode != 0:
                self.log(f"创建DMG失败: {result.stderr}", "ERROR")
                return False
                
            # 挂载DMG进行配置
            self.log("挂载DMG进行配置...")
            mount_result = subprocess.run([
                "hdiutil", "attach", str(temp_dmg), "-readwrite", "-noverify"
            ], capture_output=True, text=True)
            
            if mount_result.returncode != 0:
                self.log(f"挂载DMG失败: {mount_result.stderr}", "ERROR")
                return False
                
            # 获取挂载点
            mount_point = None
            for line in mount_result.stdout.split('\n'):
                if '/Volumes/' in line:
                    mount_point = line.split('\t')[-1].strip()
                    break
                    
            if not mount_point:
                self.log("无法找到挂载点", "ERROR")
                return False
                
            self.log(f"DMG已挂载到: {mount_point}")
            
            # 设置DMG外观（使用AppleScript）
            applescript = f'''
tell application "Finder"
    tell disk "{self.volume_name}"
        open
        set current view of container window to icon view
        set toolbar visible of container window to false
        set statusbar visible of container window to false
        set the bounds of container window to {{100, 100, 600, 400}}
        set viewOptions to the icon view options of container window
        set arrangement of viewOptions to not arranged
        set icon size of viewOptions to 128
        set position of item "{self.app_name}.app" of container window to {{150, 200}}
        set position of item "Applications" of container window to {{350, 200}}
        close
        open
        update without registering applications
        delay 2
    end tell
end tell
'''
            
            # 执行AppleScript
            try:
                subprocess.run(["osascript", "-e", applescript], 
                             capture_output=True, text=True, timeout=30)
                self.log("DMG外观设置完成")
            except subprocess.TimeoutExpired:
                self.log("DMG外观设置超时，继续...", "WARNING")
            except Exception as e:
                self.log(f"DMG外观设置失败: {e}", "WARNING")
                
            # 卸载DMG
            self.log("卸载临时DMG...")
            subprocess.run(["hdiutil", "detach", mount_point], 
                         capture_output=True)
            
            # 转换为只读压缩DMG
            self.log("转换为最终DMG...")
            cmd_convert = [
                "hdiutil", "convert", str(temp_dmg),
                "-format", "UDZO",
                "-imagekey", "zlib-level=9",
                "-o", str(self.dmg_path)
            ]
            
            result = subprocess.run(cmd_convert, capture_output=True, text=True)
            if result.returncode != 0:
                self.log(f"转换DMG失败: {result.stderr}", "ERROR")
                return False
                
            # 清理临时文件
            if temp_dmg.exists():
                temp_dmg.unlink()
                
            self.log(f"DMG创建成功: {self.dmg_path}", "SUCCESS")
            
            # 显示文件大小
            dmg_size = self.dmg_path.stat().st_size
            dmg_size_mb = dmg_size / (1024 * 1024)
            self.log(f"最终DMG大小: {dmg_size_mb:.1f}MB")
            
            return True
            
        except Exception as e:
            self.log(f"创建DMG时出错: {e}", "ERROR")
            return False
            
    def _get_directory_size(self, directory):
        """计算目录大小"""
        total_size = 0
        for dirpath, dirnames, filenames in os.walk(directory):
            for filename in filenames:
                filepath = os.path.join(dirpath, filename)
                if os.path.exists(filepath):
                    total_size += os.path.getsize(filepath)
        return total_size
        
    def create_dmg(self):
        """创建DMG的主函数"""
        self.log(f"开始创建 {self.app_name} DMG", "HEADER")
        
        # 检查要求
        if not self.check_requirements():
            return False
            
        # 使用临时目录
        with tempfile.TemporaryDirectory() as temp_dir:
            # 创建DMG结构
            dmg_content = self.create_dmg_structure(temp_dir)
            
            # 设置外观
            self.set_dmg_appearance(dmg_content)
            
            # 创建DMG文件
            if not self.create_dmg_file(dmg_content):
                return False
                
        self.log("DMG创建完成！", "SUCCESS")
        return True


def main():
    """主函数"""
    creator = DMGCreator()
    success = creator.create_dmg()
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main() 